import { pauseTrack, startTrack, track, trigger } from './effect.js'
import { hasChange, isObject } from "./utils.js";
import { TrackOpTypes } from "./operations.js";
import { TriggerOpTypes } from "./operations.js";
// 由于map存数据之后，一直保存在内存中，而weakmap会被垃圾回收器自动清理
// 这样可以避免内存泄漏
const targetMap = new WeakMap()
const RAW =  Symbol('RAW')

const proxyListFunction = {}
const listFunction = ['includes', 'indexOf', 'lastIndexOf']
listFunction.forEach(item => {
    proxyListFunction[item] = function (...args) {
        console.log('拦截数组方法')
        let res = Array.prototype[item].call(this, ...args)
        if(res<0 || res === false) {
            return Array.prototype[item].call(this[RAW], ...args)
        }
        return res
    }
})

const arrayFunction = ['pop', 'push', 'shift', 'unshift', 'splice']
arrayFunction.forEach(item => {
    proxyListFunction[item] = function (...args) {
        pauseTrack()
        const res = Array.prototype[item].call(this, ...args)
        startTrack()
        return res
    }
})

export function reactive(target) {
    if(!isObject(target)) {
        return target
    }
    if(targetMap.has(target)) {
        return targetMap.get(target)
    }
    const proxy = new Proxy(target, {
        get(target, key, receiver) {

            if(key === RAW) {
                return target
            }

            // 依赖收集
            track(target,TrackOpTypes.GET, key) //注意依赖收集时，加上操作类型

            if(proxyListFunction.hasOwnProperty(key) && Array.isArray(target)) {
                return proxyListFunction[key]
            }

            const res =  Reflect.get(target, key, receiver)
            if(isObject(res)) {
                return reactive(res)
            }
            return res
        },
        set(target, key, value, receiver) {
            const oldLength = Array.isArray(target) ? target.length : undefined
            const oldValue = target[key] // 拿旧值，需要和新值比较
            const type = target.hasOwnProperty(key)
            ? TriggerOpTypes.SET
            : TriggerOpTypes.ADD

            const res =  Reflect.set(target, key, value, receiver)
            if(!res) {
                return res
            }
            if(!hasChange(oldValue, value) || type === TriggerOpTypes.ADD) {
                trigger(target,type , key)
                if(Array.isArray(target) && oldLength!== target.length && key!=='length') {
                    trigger(target,type , 'length')
                }
                if(key === 'length'&& target.length < oldLength ) {
                    for(let i = target.length; i< oldLength; i++) {
                        trigger(target, TriggerOpTypes.DELETE, i.toString())
                    }
                }
            }

            return res
        },
        has(target, key) {
            track(target, TrackOpTypes.HAS, key)
            return Reflect.has(target, key)
        },

        ownKeys(target) {
            track(target, TrackOpTypes.ITERATE)
            return Reflect.ownKeys(target) // 拦截迭代
        },
        deleteProperty(target, key) { //拦截删除属性
            const res = Reflect.deleteProperty(target, key)
            const hasKey = target.hasOwnProperty(key)
            if(res && hasKey) {
                trigger(target, TriggerOpTypes.DELETE, key)
            }
            return res
        }

    })
    targetMap.set(target, proxy)
    return proxy
}
